package com.edu.juc.threadLocal;

import com.edu.juc.threadLocal.bean.House;

import java.lang.ref.WeakReference;
import java.util.concurrent.CountDownLatch;

/**
 * Thread/ThreadLocal/ThreadLocalMap
 * ThreadLocalMap是一个保存ThreadLocal对象的map(其实是以ThreadLocal为Key)，
 * 不过是经过了两层包装的ThreadLocal对象。
 * <p>
 * JVM内部维护了一个线程版的Map<ThreadLocal, Value> (通过ThreadLocal对象的set方法，结果把ThreadLocal对象自己当作key，放进了ThreadLocalMap中)，
 * 每个线程要用到这个T的时候，用当前线程去Map里面获取，通过这样让每个线程都拥有了自己独立的变量。
 */
public class ThreadLocalTest {
    public static void main(String[] args) {
        House house = new House();
        CountDownLatch countDownLatch = new CountDownLatch(5);
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    int random = (int) (Math.random() * 5) + 1;
                    for (int j = 0; j < random; j++) {
                        house.saleHouse();
                        house.saleVolumeByThreadLocal();
                    }
                    countDownLatch.countDown();
                    System.out.println(Thread.currentThread().getName() + ": " + house.getSaleVolume().get());
                } finally {
                    house.getSaleVolume().remove();
                }
            }, "Thread-" + i).start();
        }
        try {
            countDownLatch.await();
            System.out.println("总销售量: " + house.getSaleCount());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 源码
     * 弱引用：大概率会减少内存泄漏的问题。
     * 使用弱引用就会使ThreadLocal对象在方法执行完毕后顺利被回收，且Entry的key引用指向null。
     */
    static class Entry extends WeakReference<ThreadLocal<?>> {
        /**
         * The value associated with this ThreadLocal.
         */
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
}
